---
patternId: web-vitals-patterns/carousels/carousel-autoplay
---

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Autoplay Carousel Demo</title>
    <style>
        body {
            padding: 1em;
            font-family: system-ui;
            text-align: center;
        }
        #carousel {
            max-width: 1200px;
            display: flex;
            flex-direction: column;
            margin: 0 auto;
            position: relative;
        }
        .slide-indicators {
            display: flex;
            justify-content: center;
        }
        .slide-indicator {
            height: 44px;
            width: 50px;
            display: flex;
            justify-items: center;
            cursor: pointer;
        }
        .slide-indicator:after {
            content: "";
            background-color: #878787;
            height: 10px;
            margin-top: 10px;
            width: 40px;
        }
        .slide-indicator.active:after,
        .slide-indicator:hover:after {
            background-color: #000000;
        }
        .slide-banner {
            background-color: #000000;
            color: #ffffff;
            position: absolute;
            left: 0;
            bottom: 20px;
            padding: 15px;
            font-size: 2.5vw;
        }
        .slide-banner a {
            color: #ffffff;
        }
        #slide-container {
            scroll-snap-type: x mandatory;
            overflow-x: scroll;
            overflow-y: hidden;
            display: flex;
            align-items: center;
            height: 100%;
            gap: 10px;
            -webkit-overflow-scrolling: touch;
            scroll-behavior: smooth;
        }
        .slide {
            scroll-snap-align: center;
            position: relative;
            min-width: 100%;
            padding-top: 50%;
        }
        .slide img {
            height: 100%;
            width: auto;
            position: absolute;
            top: 0;
            left: 0;
        }
        .arrow {
            color: #ffffff;
            height: 20px;
            width: 20px;
            background-color: #000000;
            position: absolute;
            padding: 10px;
            opacity: .3;
            cursor: pointer;
        }
        .arrow.back {
            left: 10px;
            top: 10px;
        }
        .arrow.forward {
            right: 10px;
            top: 10px;
        }
        .arrow:hover {
            opacity: 1;
        }
    </style>
</head>
<body>
    <h1>Autoplay carousel</h1>
    <div id="carousel">
        <div id="slide-container">
            <div class="slide" data-slideIndex="0">
                <div class="slide-banner">Tour the Empire State Building! <a href="">Buy tickets now.</a></div>
                <img width="1200" height="600" src="https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/d5JiF2JjxniJRH6xviYA.jpg">
            </div>
            <div class="slide" data-slideIndex="1">
                <div class="slide-banner">Ride the Shinkansen! <a href="">Buy tickets now.</a></div>
                <img width="1200" height="600" src="https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/atRogpxlJTXAvhWe654i.jpg">
            </div>
            <div class="slide" data-slideIndex="2">
                <div class="slide-banner">Discover relaxation! <a href="">Buy tickets now.</a></div>
                <img width="1200" height="600" src="https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/q8svpF1B6dG5wNuiTgyV.jpg">
            </div>
            <div class="slide" data-slideIndex="3">
                <div class="slide-banner">See penguins! <a href="">Buy tickets now.</a></div>
                <img width="1200" height="600" src="https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/oweFaoCZ4g8bieZdvG5L.jpg">
            </div>
            <div class="slide" data-slideIndex="4">
                <div class="slide-banner">Take a ride on the wheel! <a href="">Buy tickets now.</a></div>
                <img width="1200" height="600" src="https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/G0aWgHwWJTPZus9YEMyH.jpg">
            </div>
        </div>
        <div id="back-button" class="arrow back">←</div>
        <div id="forward-button" class="arrow forward">→</div>
        <div class="slide-indicators">
            <div class="slide-indicator active"></div>
            <div class="slide-indicator"></div>
            <div class="slide-indicator"></div>
            <div class="slide-indicator"></div>
            <div class="slide-indicator"></div>
        </div>
    </div>
    <p>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
        incididunt ut labore et dolore magna aliqua. Maecenas volutpat blandit aliquam etiam
        erat velit. Integer eget aliquet nibh praesent. Sit amet mattis vulputate enim nulla.
        Faucibus nisl tincidunt eget nullam non. Sem fringilla ut morbi tincidunt augue.
        Sed id semper risus in hendrerit gravida rutrum quisque non. Blandit aliquam etiam
        erat velit scelerisque in dictum non consectetur. Et ultrices neque ornare aenean
        euismod. Dignissim sodales ut eu sem integer vitae justo. Justo eget magna fermentum
        iaculis eu non diam phasellus.
    </p>
    {% set script %}
        function autoplayCarousel(){
            const carouselEl = document.getElementById("carousel");
            const slideContainerEl = carouselEl.querySelector("#slide-container");
            const slideEl = carouselEl.querySelector(".slide");
            let slideWidth = slideEl.offsetWidth;
            // Add click handlers
            document.querySelector("#back-button")
                .addEventListener("click", () => navigate("backward"));
            document.querySelector("#forward-button")
                .addEventListener("click", () => navigate("forward"));
            document.querySelectorAll(".slide-indicator")
                .forEach((dot, index) => {
                    dot.addEventListener("click", () => navigate(index));
                    dot.addEventListener("mouseenter", () => clearInterval(autoplay));
                });
            // Add keyboard handlers
            document.addEventListener('keydown', (e) => {
                if (e.code === 'ArrowLeft') {
                    clearInterval(autoplay);
                    navigate("backward");
                } else if (e.code === 'ArrowRight') {
                    clearInterval(autoplay);
                    navigate("forward");
                }
            });
            // Add resize handler
            window.addEventListener('resize', () => {
                slideWidth = slideEl.offsetWidth;
            });
            // Autoplay
            const autoplay = setInterval(() => navigate("forward"), 3000);
            slideContainerEl.addEventListener("mouseenter", () => clearInterval(autoplay));
            // Slide transition
            const getNewScrollPosition = (arg) => {
                const gap = 10;
                const maxScrollLeft = slideContainerEl.scrollWidth - slideWidth;
                if (arg === "forward") {
                    const x = slideContainerEl.scrollLeft + slideWidth + gap;
                    return x <= maxScrollLeft ? x : 0;
                } else if (arg === "backward") {
                    const x = slideContainerEl.scrollLeft - slideWidth - gap;
                    return x >= 0 ? x : maxScrollLeft;
                } else if (typeof arg === "number") {
                    const x = arg * (slideWidth + gap);
                    return x;
                }
            }
            const navigate = (arg) => {
                slideContainerEl.scrollLeft = getNewScrollPosition(arg);
            }
            // Slide indicators
            const slideObserver = new IntersectionObserver((entries, observer) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        const slideIndex = entry.target.dataset.slideindex;
                        carouselEl.querySelector('.slide-indicator.active').classList.remove('active');
                        carouselEl.querySelectorAll('.slide-indicator')[slideIndex].classList.add('active');
                    }
                });
            }, { root: slideContainerEl, threshold: .1 });
            document.querySelectorAll('.slide').forEach((slide) => {
                slideObserver.observe(slide);
            });
        }
        autoplayCarousel();
    {% endset %}
    <script>{{ script | minifyJs | cspHash | safe }}</script>
</body>
